package com.txw.javaCore.server.service.redis;

import com.txw.javaCore.model.dto.PraiseRankDto;
import com.txw.javaCore.model.mapper.PraiseMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RList;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @PROJECT_NAME: JavaCoreB2
 * @DESCRIPTION: 博客点赞处理服务
 * @Author: 涂玄武
 * @DATE: 2021/3/22 16:27
 */
@Component
@Slf4j
public class RedisPraise {

    //定义点赞博客时缓存存储时Key
    private static final String keyBlog = "RedisBlogPraiseMap";

    //定义用于缓存排行榜的Key
    private static final String keyList = "praiseRankListKey";

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private PraiseMapper praiseMapper;

    /**
     * 缓存当前用户点赞博客的记录
     *
     * @param blogId
     * @param uId
     * @param status
     * @throws Exception
     */
    public void cachePraiseBlog(Integer blogId, Integer uId, Integer status) throws Exception {
        //创建用户获取分布式锁的Key
        final String lockName = new StringBuffer("blogRedissonPraiseLock").append(blogId).append(uId).append(status).toString();
        //获取分布式锁实例
        RLock rLock = redissonClient.getLock(lockName);
        //尝试获取分布式锁（可重入锁）:第一个参数是等待时间，5秒内获取不到锁，则直接返回。 第二个参数 10秒后强制释放
        boolean res = rLock.tryLock(5L, 10L, TimeUnit.SECONDS);
        try {
            if (res) {
                if (blogId != null && uId != null && status != null) {
                    //采用“博客id+用户id”的拼接作为key
                    final String key = blogId + ":" + uId;
                    //定义Redisson的RMap映射数据类型实例
                    RMap<String, Integer> praiseMap = redissonClient.getMap(keyBlog);
                    //status=1,代表点赞;status=0,代表取消点赞
                    if (1 == status) {
                        praiseMap.put(key, uId);
                    } else if (0 == status) {
                        praiseMap.remove(key);
                    }

                }
            }
        } catch (Exception e) {
            throw e;
        } finally {
            //操作完毕，直接释放该锁
            if (rLock != null) {
                rLock.forceUnlock();
            }
        }
    }

    /**
     * 获取博客总的点赞数
     *
     * @param blogId
     * @return
     * @throws Exception
     */
    public Long getCacheTotalBlog(Integer blogId) throws Exception {
        //定义最终的返回值，初始值为0
        Long result = 0L;
        //判断参数的合法性
        if (blogId != null) {
            RMap<String, Integer> praiseMap = redissonClient.getMap(keyBlog);
            //获取RMap中所有的键值对列表
            Map<String, Integer> dataMap = praiseMap.readAllMap();
            //判断取出的键值对列表是否有值
            if (dataMap != null && dataMap.keySet() != null) {
                Set<String> set = dataMap.keySet();
                Integer bId;
                for (String key : set) {
                    //key:"博客id:用户id"
                    if (StringUtils.isNotBlank(key)) {
                        String[] arr = key.split(":");
                        if (arr != null && arr.length > 0) {
                            bId = Integer.valueOf(arr[0]);
                            if (blogId.equals(bId)){
                                result += 1;
                            }
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 博客点赞排行榜
     * @throws Exception
     */
    public void rankBlogPraise() throws Exception{
        //根据数据库查询语句得到已排序好的博客实体对象列表
        List<PraiseRankDto> praiseRank = praiseMapper.getPraiseRank();
        //判断列表中是否有数据
        if (!CollectionUtils.isEmpty(praiseRank)){
            RList<PraiseRankDto> rList = redissonClient.getList(keyList);
            //先清空缓存中的列表数据
            rList.clear();
            //将得到的最新的排行榜数据更新至缓存中
            rList.addAll(praiseRank);
        }
    }

    /**
     * 获取博客点赞排行榜
     * @return
     * @throws Exception
     */
    public List<PraiseRankDto> getBlogPraiseRank() throws Exception{
        RList<PraiseRankDto> rList = redissonClient.getList(keyList);
        return rList.readAll();
    }
}
